package com.mars.framework.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mars.common.constant.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 记录rest接口请求和响应日志
 *
 * @author 程序员Mars
 */
@Aspect
@Component
@Order(1)
@Slf4j
public class GlobalLogAspect {


    @Around("@within(org.springframework.web.bind.annotation.RestController)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();
        String token = request.getHeader(Constant.TOKEN);
        String requestUri = request.getRequestURI();
        StopWatch stopWatch = StopWatch.createStarted();
        Object result = joinPoint.proceed(joinPoint.getArgs());
        stopWatch.stop();
        log.info("\n{ \n请求地址:【{}】 \n请求参数:【{}】  \n请求Token:【{}】 \n请求方式:【{}】 \n请求类方法:{} \n请求耗时:【{}】毫秒 \n响应参数:【{}】 \n}",
                requestUri,
                JSONObject.toJSONString(filterArgs(joinPoint.getArgs(), request)),
                token,
                request.getMethod(),
                joinPoint.getSignature(),
                stopWatch.getTime(TimeUnit.MILLISECONDS), JSONObject.toJSONString(result));
        return result;
    }

    private String filterArgs(Object[] objects, HttpServletRequest request) throws IllegalAccessException {
        Map<String, String> map = new HashMap<>(16);
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            map.put(name, request.getParameter(name));
        }
        String result = "";
        String method = request.getMethod();
        if (objects.length > 0) {
            try {
                if ("POST".equals(method)) {
                    Object object = objects[0];
                    Map<String, Object> bodyMap = getKeyAndValue(object);
                    if (MapUtils.isNotEmpty(bodyMap)) {
                        result = JSON.toJSONString(bodyMap);
                    }
                } else {
                    result = JSONObject.toJSONString(map);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static Map<String, Object> getKeyAndValue(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>(16);
        // 得到类对象
        Class<?> userCla = obj.getClass();
        //得到类中的所有属性集合
        Field[] fs = userCla.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            // 设置些属性是可以访问的
            f.setAccessible(true);
            Object val = f.get(obj);
            // 得到此属性的值 设置键值
            map.put(f.getName(), val);

        }
        return map;
    }
}

